/**
 * 项目名：	Rumba Plan
 * 
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2006，所有权利保留。
 * 
 * 文件名：	BPermAgent.java
 * 模块说明：	
 * 修改历史：
 * 2006-10-4 - lxm - 创建。
 */
package com.hd123.rumba.user.biz;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.type.Type;

import com.hd123.rumba.cartridge.ICartFunctionView;
import com.hd123.rumba.cartridge.ICartridgeMgr;
import com.hd123.rumba.cartridge.biz.SCartFunctionView;
import com.hd123.rumba.domain.IDomainFuncView;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.gwt.base.client.exception.ClientBizException;
import com.hd123.rumba.runtime.IBaseEntity;
import com.hd123.rumba.runtime.IManager;
import com.hd123.rumba.runtime.IVersionedPersistent;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.sql.ResultPage;
import com.hd123.rumba.sql.SCE;
import com.hd123.rumba.sql.SQLSubquery;
import com.hd123.rumba.user.CPermission;
import com.hd123.rumba.user.CRole;
import com.hd123.rumba.user.IPermission;
import com.hd123.rumba.user.IPermissionMgr;
import com.hd123.rumba.user.IRole;
import com.hd123.rumba.user.IUser;
import com.hd123.rumba.user.PermissionProvider;
import com.hd123.rumba.util.ClassifiedHashtable;
import com.hd123.rumba.util.StringUtil;

/**
 * 权限维护代理基类 | 业务层 | 实现类
 * 
 * @author lxm
 * 
 */
public abstract class BPermAgent {

  protected String urUuid = null;
  protected String[] domainUuids = null;

  public String getUserOrRoleUuid() throws BusinessException {
    return urUuid;
  }

  public void setUserOrRoleUuid(String userOrRoleUuid) throws BusinessException {
    urUuid = userOrRoleUuid;
  }

  public BPermGroupAssign getGlobalPermGroup() throws BusinessException, HibernateException {
    checkIn();
    BPermGroupAssign pga = new BPermGroupAssign();
    List list = getSession().find(
        "select count(distinct p) from " + IPermission.class.getName() + " p, "
            + IDomainFuncView.class.getName() + " dfv"
            + " where dfv.funcView.uuid = p.cartFuncViewUuid and dfv.domain.uuid in "
            + StringUtil.ArrayToInString(domainUuids, "'"));
    if (list.size() > 0)
      pga.setPermCount((Integer) list.get(0));
    else
      pga.setPermCount(new Integer(0));
    pga.setCheckedPermCount(getHavingPermCount());
    return pga;
  }

  public List<BPermGroupAssign> getCFVPermGroups() throws BusinessException, HibernateException {
    checkIn();
    List<BPermGroupAssign> pgas = new ArrayList();
    List list = getSession().find(
        "select p.cartFuncViewUuid, count(distinct p) from " + IPermission.class.getName() + " p, "
            + IDomainFuncView.class.getName() + " dfv"
            + " where dfv.funcView.uuid = p.cartFuncViewUuid and dfv.domain.uuid in "
            + StringUtil.ArrayToInString(domainUuids, "'") + " group by p.cartFuncViewUuid");
    for (int i = 0; i < list.size(); i++) {
      Object[] record = (Object[]) list.get(i);
      BPermGroupAssign pga = new BPermGroupAssign();
      SCartFunctionView scfv = getFunctionView((String) record[0]);
      pga.setCartFunctionView(scfv);
      pga.setPermCount((Integer) record[1]);
      pga.setCheckedPermCount(getHavingPermCountInCFV(scfv.getUuid()));
      pgas.add(pga);
    }
    sortPermGroupAssignList(pgas);
    return pgas;
  }

  public List<BPermGroupAssign> getProviderPermGroups(String cfvUuid) throws BusinessException,
      HibernateException {
    checkIn();
    List<BPermGroupAssign> pgas = new ArrayList();
    SCartFunctionView scfv = getFunctionView(cfvUuid);
    List list = getSession().find(
        "select p.provider, count(p)" + " from " + IPermission.class.getName() + " p"
            + " where p.cartFuncViewUuid = ?"
            + " group by p.provider.type, p.provider.className, p.provider.caption", cfvUuid,
        Hibernate.STRING);
    for (int i = 0; i < list.size(); i++) {
      Object[] record = (Object[]) list.get(i);
      BPermGroupAssign pga = new BPermGroupAssign();
      pga.setCartFunctionView(scfv);
      PermissionProvider pprovider = (PermissionProvider) record[0];
      BPermissionProvider provider = new BPermissionProvider();
      provider.readFrom(pprovider);
      pga.setProvider(provider);
      pga.setPermCount((Integer) record[1]);
      pga.setCheckedPermCount(getHavingPermCountInProvider(cfvUuid, provider));
      pgas.add(pga);
    }
    sortPermGroupAssignList(pgas);
    return pgas;
  }

  public List<BBasePermAssign> getPermissions(String cfvUuid, String providerClassName)
      throws BusinessException, HibernateException {
    checkIn();
    List<BBasePermAssign> pas = new ArrayList();
    SCartFunctionView scfv = getFunctionView(cfvUuid);
    List list = getSession().find(
        "from " + IPermission.class.getName() + " p"
            + " where p.cartFuncViewUuid = ? and p.provider.className = ?", new Object[] {
            cfvUuid, providerClassName }, new Type[] {
            Hibernate.STRING, Hibernate.STRING });
    for (int i = 0; i < list.size(); i++) {
      IPermission pperm = (IPermission) list.get(i);
      boolean isNew = true;
      if (pperm.getFieldCaption() == null) {
        BPermAssign pa = new BPermAssign();
        SPermission perm = new SPermission();
        perm.readFrom(pperm);
        pa.setPermission(perm);
        pa.setValue(hasPermission(pperm));
        pas.add(pa);
      } else {
        BFieldPermAssign fpa = seekFieldPermAssign(pas, pperm.getFieldCaption());
        if (fpa == null) {
          fpa = new BFieldPermAssign();
          fpa.setCartFunctionView(scfv);
          BPermissionProvider provider = new BPermissionProvider();
          provider.readFrom(pperm.getProvider());
          fpa.setProvider(provider);
          fpa.setFieldCaption(pperm.getFieldCaption());
        } else
          isNew = false;
        SPermission perm = new SPermission();
        perm.readFrom(pperm);
        Integer value = BFieldPermAssign.VALUE_VALUE_INVISIBLE;
        // if (pperm.getCode().matches(".*\\.修改权\\z")) {
        if (pperm.getCode().endsWith(CPermission.SUFFIX_PERMISSION_EDIT)) {
          fpa.setWritablePermission(perm);
          if (hasPermission(pperm).booleanValue())
            value = BFieldPermAssign.VALUE_VALUE_WRITABLE;
        } else {
          fpa.setReadonlyPermission(perm);
          if (hasPermission(pperm).booleanValue())
            value = BFieldPermAssign.VALUE_VALUE_READONLY;
        }
        fpa.setValue(Integer.valueOf(Math.max(fpa.getValue().intValue(), value.intValue())));
        if (isNew)
          pas.add(fpa);
      }
    }
    sortPermAndFieldAssignList(pas);
    return pas;
  }

  /** 根据uuid取得实体对象 */
  protected abstract IBaseEntity getUserOrRole(String urUuid) throws BusinessException,
      HibernateException;

  /** 取得用户或角色管理员对象 */
  protected abstract IManager getUserOrRoleMgr() throws BusinessException;

  /** 取得当前对象所拥有的权限的数量。 */
  protected abstract Integer getHavingPermCount() throws BusinessException, HibernateException;

  /** 取得在指定构件包功能视图中当前对象所拥用的权限的数量。 */
  protected abstract Integer getHavingPermCountInCFV(String cfvUuid) throws BusinessException,
      HibernateException;

  /** 取得在指定权限提供者范围内当前对象所拥有的权限的数量。 */
  protected abstract Integer getHavingPermCountInProvider(String cfvUuid,
      BPermissionProvider provider) throws BusinessException, HibernateException;

  /** 在当前对象拥有权限集合中检查是否已经拥有指定的权限。 */
  protected abstract Boolean hasPermission(IPermission pperm) throws BusinessException,
      HibernateException;

  private IPermissionMgr permMgr = null;
  private ICartridgeMgr cartMgr = null;

  protected IPermissionMgr getPermMgr() throws BusinessException {
    if (permMgr == null)
      permMgr = (IPermissionMgr) NamingMgr.getInstance().lookupMgr(IPermissionMgr.class);
    return permMgr;
  }

  private ICartridgeMgr getCartMgr() throws BusinessException {
    if (cartMgr == null)
      cartMgr = (ICartridgeMgr) NamingMgr.getInstance().lookupMgr(ICartridgeMgr.class);
    return cartMgr;
  }

  protected void checkIn() throws BusinessException, HibernateException {
    if (urUuid == null)
      throw new BusinessException("指定属性userOrRoleUuid不可为空。");
    IBaseEntity entity = getUserOrRole(this.urUuid);
    if (entity instanceof IUser) {
      domainUuids = new String[1];
      domainUuids[0] = entity.getDomain().getUuid();
    } else if (entity instanceof IRole) {
      IRole role = (IRole) entity;
      // 如果是公共角色，取得所有共享该公共角色的域的uuid列表
      if (CRole.VALUE_ROLETYPE_PUBLIC.equals(role.getRoleType())) {
        List list = getSession().find(
            "select o.domain.uuid from IRoleDomain o where o.role.uuid = ?", role.getUuid(),
            Hibernate.STRING);
        domainUuids = new String[list.size()];
        for (int i = 0; i < list.size(); i++)
          domainUuids[i] = (String) list.get(i);
      } else {
        domainUuids = new String[1];
        domainUuids[0] = entity.getDomain().getUuid();
      }
    } else
      throw new BusinessException("无法识别的对象类型：" + entity.getClass().getName());
  }

  protected Session getSession() throws BusinessException, HibernateException {
    return getUserOrRoleMgr().getSession();
  }

  protected ClassifiedHashtable checkOca(IVersionedPersistent entity, long oca,
      String classCaption, String entitySpec) throws BusinessException {
    if (entity.getUuid() != null && entity.getOca() != oca) {
      ClassifiedHashtable h = new ClassifiedHashtable();
      h.putMessage("oca", ClassifiedHashtable.ERROR, "指定" + classCaption + "[" + entitySpec
          + "]已经被其他用户修改，操作将被取消。");
      return h;
    } else
      return null;
  }

  /** 取得权限命令所涉及的权限列表。 */
  protected List fetchPermsByCmd(BPermissionCommand cmd) throws BusinessException,
      HibernateException {
    SQLSubquery sq = new SQLSubquery();
    sq.addSelect("p.code");
    sq.addFrom(IPermission.class.getName(), "p");
    sq.addFrom(IDomainFuncView.class.getName(), "dfv");
    SCE cond = new SCE(SCE.VALUE_OPERATOR_AND);
    cond.append(SCE.cond("p.cartFuncViewUuid = dfv.funcView.uuid"));
    cond.append(SCE.cond("dfv.domain.uuid in ?", domainUuids));
    if (cmd.getPermissionCode() != null)
      cond.append(SCE.cond("p.code = ?", cmd.getPermissionCode()));
    else {
      if (cmd.getCartFunctionViewUuid() != null)
        cond.append(SCE.cond("p.cartFuncViewUuid = ?", cmd.getCartFunctionViewUuid()));
      if (cmd.getProviderClassName() != null)
        cond.append(SCE.cond("p.provider.className = ?", cmd.getProviderClassName()));
      if (cmd.getFieldCaption() != null)
        cond.append(SCE.cond("p.fieldCaption = ?", cmd.getFieldCaption()));
    }
    sq.setWhere(cond);
    ResultPage rp = ResultPage.createHibernateResultPage(getSession(), sq, 0, 0);
    return rp.getContentList();
  }

  /** 在内存权限表中加入权限列表指定的权限。 */
  protected void updateToCheckPerms(List permList, Map<String, String> permMap) {
    for (int i = 0; i < permList.size(); i++) {
      String permCode = (String) permList.get(i);
      permMap.put(permCode, permCode);
    }
  }

  /** 在内存权限表中删除权限列表指定的权限。 */
  protected void updateToUncheckPerms(List permList, Map<String, String> permMap) {
    for (int i = 0; i < permList.size(); i++) {
      String permCode = (String) permList.get(i);
      permMap.remove(permCode);
    }
  }

  /** 修改内存权限表，在指定的权限列表中删除所有的修改权限并添加所有的查看权。 */
  protected void updateToReadOnlyPerms(List permList, Map<String, String> permMap) {
    for (int i = 0; i < permList.size(); i++) {
      String permCode = (String) permList.get(i);
      if (permCode.matches(".*\\.修改权\\z"))
        permMap.remove(permCode);
      else if (permCode.matches(".*\\.查看权\\z"))
        permMap.put(permCode, permCode);
    }
  }

  /** 根据uuid取得构件包功能视图。 */
  private SCartFunctionView getFunctionView(String cfvUuid) throws BusinessException,
      HibernateException {
    ICartFunctionView cfv = getCartMgr().getFunctionView(cfvUuid);
    SCartFunctionView scfv = new SCartFunctionView();
    try {
      if (cfv == null)
        scfv.setUuid(cfvUuid);
      else
        scfv.readFrom(cfv);
    } catch (ClientBizException e) {
      throw new BusinessException(e);
    }
    return scfv;
  }

  /** 在权限赋值列表中搜索相同字段名的字段权限赋值对象。若找不到则返回null。 */
  private BFieldPermAssign seekFieldPermAssign(List<BBasePermAssign> pas, String fieldCaption)
      throws BusinessException {
    BFieldPermAssign fpa = null;
    for (int i = 0; i < pas.size(); i++) {
      if (!(pas.get(i) instanceof BFieldPermAssign))
        continue;
      BFieldPermAssign fpa2 = (BFieldPermAssign) pas.get(i);
      if (fpa2.getFieldCaption().equals(fieldCaption)) {
        fpa = fpa2;
        break;
      }
    }
    return fpa;
  }

  private void sortPermGroupAssignList(List<BPermGroupAssign> pgas) {
    // Do Nothing，由页面提供排序功能。
  }

  private void sortPermAndFieldAssignList(List<BBasePermAssign> pas) {
    // Do Nothing，由页面提供排序功能。
  }

}
